/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


/*************************************************************************
 * File: codec.h
 *************************************************************************
 *\author: starlove
 *************************************************************************/

#ifndef __MLSE_CODEC_CODEC_H__
#define __MLSE_CODEC_CODEC_H__

#define __BUFFER_SIZE__ (1024 * 96)

#include <platform/platform.h>
#include <string.h>

enum DATA_TP
{
    DTP_NULL	= 0,
    DTP_INT		= 1,
    DTP_INT64	= 2,
    DTP_STR		= 3,
    DTP_FLOAT	= 4,
    DTP_BOOL	= 5,
    DTP_DOUBLE	= 6,
    DTP_MAP		= 7,
    DTP_LIST	= 8,
    DTP_BUFFER	= 9,
    DTP_PBUFFER	= 10
};

typedef const char *ENCODESTR;
typedef std::string CODE_HASH_KEY;

#pragma pack(1)

typedef struct __WRAPPER_DATA_HEADER
{
    char tp;
    unsigned int size;

    __WRAPPER_DATA_HEADER()
    {
        size = 0;
    }
} WRAPPER_DATA_HEADER, *LPWRAPPER_DATA_HEADER;

typedef struct __WRAPPER_KEYVALUE_DATA_HEADER
{
    char tp;
    unsigned int size;
    char ktp;
    unsigned int ksize;

    __WRAPPER_KEYVALUE_DATA_HEADER()
    {
        size = 0;
        ksize = 0;
    }
} WRAPPER_KEYVALUE_DATA_HEADER, *LPWRAPPER_KEYVALUE_DATA_HEADER;

typedef struct __BUFFER_WRAPPER
{
    unsigned int size;
    unsigned char *data;
    unsigned char *curr;
    unsigned char *end;

    unsigned char *out_data;
    unsigned char *out_curr;
    bool alloc_access;

    void init(void *in_buf, unsigned int in_size)
    {
        data = (unsigned char *)in_buf;
        curr = data;
        end  = data + in_size;
        out_curr = data;
        alloc_access = true;
        size = end - curr;
    }

    void setbuf(void *in_buf, unsigned int in_size)
    {
        init(in_buf, in_size);
        curr = end;
    }

    void readonly_ref(void *buf, unsigned int nsize)
    {
        data = (unsigned char *)buf;
        out_curr = data;
        alloc_access = true;
        size = nsize;
        end = curr = data + size;
    }

    void __write(const void *p, unsigned int nsize)
    {
        memcpy(curr, p, nsize);
        curr += nsize;
        size = end - curr;
    }

    bool alloc(unsigned int nsize)
    {
        if (!alloc_access)
            return false;
        if(size < nsize + sizeof(nsize))
            return false;

        alloc_access = false;
        return true;
    }

    void flush()
    {
        alloc_access = true;
    }

    bool push(const void *p, unsigned int nsize)
    {
        __write(p, nsize);
        return true;
    }

    bool copyfrom(const void *p, unsigned int nsize)
    {
        if (nsize > size)
            return false;
        memcpy(data, p, nsize);
        curr = data + nsize;
        size = end - curr;
        return true;
    }

    void *read(unsigned int nsize)
    {
        if (!alloc_access)
            return NULL;
        if(out_curr + nsize > curr)
            return NULL;
        void *p = out_curr;
        out_curr += nsize;
        return p;
    }

    bool forward(int nsize = -1)
    {
		if(nsize >= 0)
		{
			if(out_curr - nsize < data)
				return false;
			out_curr -= nsize;
		}else
		{
			out_curr = data;
		}
        return true;
    }

    bool skip(unsigned int nsize)
    {
        if(out_curr + nsize > curr)
            return false;
        out_curr += nsize;
        return true;
    }

    const char *readstr()
    {
        if (!alloc_access)
            return NULL;
        const char *p = (const char *)out_curr;
        unsigned int strsize = strlen(p) + 1;
        if(out_curr + strsize > curr)
            return NULL;
        out_curr += strsize;
        return p;
    }

    void reset()
    {
        curr = out_curr = data;
    }

    unsigned int data_size()
    {
        return (unsigned int)(curr - data);
    }
} BUFFER_WRAPPER, *LPBUFFER_WRAPPER;

#pragma pack()

class IExData
{
public:
    virtual void Load(LPBUFFER_WRAPPER pBuffer) = 0;
    virtual unsigned int GetSize() = 0;
};
typedef IExData *LPData;

class IEncoder
{
public:
    virtual ~IEncoder() {};
    virtual LPBUFFER_WRAPPER Encode(LPBUFFER_WRAPPER pDstBuffer, void *pSrc) = 0;
};

class IDecoder
{
public:
    virtual ~IDecoder() {};
    virtual void *Decode(LPBUFFER_WRAPPER pSrcBuffer, void *pDst) = 0;
};

typedef IEncoder *LPIEncoder;
typedef IDecoder *LPIDecoder;

class ICodec
{
public:
    virtual LPIEncoder GetEncoder() = 0;
    virtual LPIDecoder GetDecoder() = 0;
};

class CMapData;
class CListData;

#endif	//
